import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  EventEmitter,
  Input, OnChanges,
  OnDestroy,
  OnInit,
  Output, SimpleChanges,
  TemplateRef,
  ViewChild,
} from '@angular/core';

import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import { isInteger } from '../core/util/check';
import { InputBoolean, InputNumber,toNumber } from '../core/util/convert';
import { ApesI18nService } from '../i18n/apes-i18n.service';
export interface PaginationItemRenderContext {
  $implicit: 'page' | 'prev' | 'next';
  page: number;
}
@Component({
  selector: 'apes-pagination',
  exportAs: 'apesPagination',
  preserveWhitespaces: false,
  changeDetection: ChangeDetectionStrategy.OnPush,
  templateUrl        : './apes-pagination.component.html'
})
export class ApesPaginationComponent implements OnInit, OnDestroy, OnChanges {
  prefixCls ="apes-pagination";
  locale: any = {};
  firstIndex = 1;
  pages: number[] = [];
  private $destroy = new Subject<void>();
  @Output() readonly apesPageSizeChange: EventEmitter<number> = new EventEmitter();
  @Output() readonly apesPageIndexChange: EventEmitter<number> = new EventEmitter();
  @Input() apesShowTotal: TemplateRef<{ $implicit: number, range: [ number, number ] }>;
  @Input() apesInTable = false;
  @Input() apesSize: string;
  @Input() apesPageSizeOptions = [10, 20, 30, 40];

  @Input() apesItemRender: TemplateRef<PaginationItemRenderContext>;
  @ViewChild('renderItemTemplate', { static: true }) apesItemRenderChild: TemplateRef<PaginationItemRenderContext>;
  get itemRender(): TemplateRef<PaginationItemRenderContext> {
    return this.apesItemRender || this.apesItemRenderChild;
  }
  @Input() @InputBoolean() apesDisabled = false;
  @Input() @InputBoolean() apesShowSizeChanger = false;
  @Input() @InputBoolean() apesHideOnSinglePage = false;
  @Input() @InputBoolean() apesShowQuickJumper = false;
  @Input() @InputBoolean() apesSimple = false;
  @Input() @InputNumber() apesTotal = 0;
  @Input() @InputNumber() apesPageIndex = 1;
  @Input() @InputNumber() apesPageSize = 10;


  validatePageIndex(value: number): number {
    if (value > this.lastIndex) {
      return this.lastIndex;
    } else if (value < this.firstIndex) {
      return this.firstIndex;
    } else {
      return value;
    }
  }
  updatePageIndexValue(page: number): void {
    this.apesPageIndex = page;
    this.apesPageIndexChange.emit(this.apesPageIndex);
    this.buildIndexes();
  }

  isPageIndexValid(value: number): boolean {
    return this.validatePageIndex(value) === value;
  }
  jumpPage(index: number): void {
    if (index !== this.apesPageIndex && !this.apesDisabled) {
      const pageIndex = this.validatePageIndex(index);
      if (pageIndex !== this.apesPageIndex) {
        this.updatePageIndexValue(pageIndex);
      }
    }
  }
  jumpDiff(diff: number): void {
    this.jumpPage(this.apesPageIndex + diff);
  }
  onPageSizeChange($event: number): void {
    if(!$event) return;
    this.apesPageSize = $event;
    this.apesPageSizeChange.emit($event);
    this.buildIndexes();
    if (this.apesPageIndex > this.lastIndex) {
      this.updatePageIndexValue(this.lastIndex);
    }
  }

  handleKeyDown(_: KeyboardEvent, input: HTMLInputElement, clearInputValue: boolean): void {
    const target = input;
    const page = toNumber(target.value, this.apesPageIndex);
    if (isInteger(page) && this.isPageIndexValid(page) && page !== this.apesPageIndex) {
      this.updatePageIndexValue(page);
    }
    if (clearInputValue) {
      target.value = '';
    } else {
      target.value = `${this.apesPageIndex}`;
    }
  }
  buildIndexes(): void {
    const pages: number[] = [];
    if (this.lastIndex <= 9) {
      for (let i = 2; i <= this.lastIndex - 1; i++) {
        pages.push(i);
      }
    } else {
      const current = +this.apesPageIndex;
      let left = Math.max(2, current - 2);
      let right = Math.min(current + 2, this.lastIndex - 1);
      if (current - 1 <= 2) {
        right = 5;
      }
      if (this.lastIndex - current <= 2) {
        left = this.lastIndex - 4;
      }
      for (let i = left; i <= right; i++) {
        pages.push(i);
      }
    }
    this.pages = pages;
    this.cdr.markForCheck();
  }

  get lastIndex(): number {
    return Math.ceil(this.apesTotal / this.apesPageSize);
  }

  get isLastIndex(): boolean {
    return this.apesPageIndex === this.lastIndex;
  }

  get isFirstIndex(): boolean {
    return this.apesPageIndex === this.firstIndex;
  }

  get ranges(): number[] {
    return [(this.apesPageIndex - 1) * this.apesPageSize + 1, Math.min(this.apesPageIndex * this.apesPageSize, this.apesTotal)];
  }

  get showAddOption(): boolean {
    return this.apesPageSizeOptions.indexOf(this.apesPageSize) === -1;
  }

  constructor(private i18n: ApesI18nService, private cdr: ChangeDetectorRef) {}

  ngOnInit(): void {
    this.i18n.localeChange.pipe(takeUntil(this.$destroy)).subscribe(() => {
      this.locale = this.i18n.getLocaleData('Pagination');
      this.cdr.markForCheck();
    });
  }

  ngOnDestroy(): void {
    this.$destroy.next();
    this.$destroy.complete();
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.apesTotal || changes.apesPageSize || changes.apesPageIndex) {
      this.buildIndexes();
    }
  }
}
